﻿///Code based on
/// http://chessbin.com/page/Chess-Game-Starer-Kit.aspx

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Core.Models.Enums;

namespace Core.Models
{
    public class GameState
    {
        #region vars

        internal Board ChessBoard;
        internal Board PreviousChessBoard;
        internal Dictionary<string, int> fileToInt = new Dictionary<string, int> { { "a", 0 }, { "b", 1 }, { "c", 2 }, { "d", 3 }, { "e", 4 }, { "f", 5 }, { "g", 6 }, { "h", 7 } };

        #endregion

        #region properties

        public ChessPieceColor WhoseMove
        {
            get { return ChessBoard.WhoseMove; }
            set { ChessBoard.WhoseMove = value; }
        }

        #endregion

        #region Constructors
        public GameState()
        {
            InitiateBoard("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
        }

        public GameState(string fen)
        {
            InitiateBoard(fen);
        }

        #endregion

        #region Methods
        /// <summary>
        /// initialise the board from a FEN
        /// </summary>
        /// <param name="fen"></param>
        private void InitiateBoard(string fen)
        {
            //HumanPlayer = ChessPieceColor.White;
            ChessBoard = new Board(fen);
            PieceMoves.InitiateChessPieceMotion();
            GenerateValidMoves();
        }

        private void GenerateValidMoves()
        {
            PieceValidMoves.GenerateValidMoves(ChessBoard);
        }

        public byte[] GetEnPassantMoves()
        {
            if (ChessBoard == null)
            {
                return null;
            }

            var returnArray = new byte[2];

            returnArray[0] = (byte)(ChessBoard.EnPassantPosition % 8);
            returnArray[1] = (byte)(ChessBoard.EnPassantPosition / 8);

            return returnArray;
        }

        public bool IsValidMove(byte sourceColumn, byte sourceRow, byte destinationColumn, byte destinationRow)
        {
            if (ChessBoard == null)
            {
                return false;
            }

            if (ChessBoard.Squares == null)
            {
                return false;
            }

            byte index = GetBoardIndex(sourceColumn, sourceRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return false;
            }

            foreach (byte bs in ChessBoard.Squares[index].Piece.ValidMoves)
            {
                if (bs % 8 == destinationColumn)
                {
                    if ((byte)(bs / 8) == destinationRow)
                    {
                        return true;
                    }
                }
            }

            index = GetBoardIndex(destinationColumn, destinationRow);

            if (index == ChessBoard.EnPassantPosition)
            {
                return true;
            }

            return false;
        }

        public ChessPieceType GetPieceTypeAt(byte boardColumn, byte boardRow)
        {
            byte index = GetBoardIndex(boardColumn, boardRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return ChessPieceType.None;
            }

            return ChessBoard.Squares[index].Piece.PieceType;
        }

        public ChessPieceType GetPieceTypeAt(byte index)
        {
            if (ChessBoard.Squares[index].Piece == null)
            {
                return ChessPieceType.None;
            }

            return ChessBoard.Squares[index].Piece.PieceType;
        }

        public ChessPieceColor GetPieceColorAt(byte boardColumn, byte boardRow)
        {
            byte index = GetBoardIndex(boardColumn, boardRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return ChessPieceColor.White;
            }
            return ChessBoard.Squares[index].Piece.PieceColor;
        }

        public ChessPieceColor GetPieceColorAt(byte index)
        {
            if (ChessBoard.Squares[index].Piece == null)
            {
                return ChessPieceColor.White;
            }
            return ChessBoard.Squares[index].Piece.PieceColor;
        }

        public bool GetChessPieceSelected(byte boardColumn, byte boardRow)
        {
            byte index = GetBoardIndex(boardColumn, boardRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return false;
            }

            return ChessBoard.Squares[index].Piece.Selected;
        }

        public byte[][] GetValidMoves(byte boardColumn, byte boardRow)
        {
            byte index = GetBoardIndex(boardColumn, boardRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return null;
            }

            var returnArray = new byte[ChessBoard.Squares[index].Piece.ValidMoves.Count][];
            int counter = 0;

            foreach (byte square in ChessBoard.Squares[index].Piece.ValidMoves)
            {
                returnArray[counter] = new byte[2];
                returnArray[counter][0] = (byte)(square % 8);
                returnArray[counter][1] = (byte)(square / 8);
                counter++;
            }

            return returnArray;
        }

        public void SetChessPieceSelection(byte boardColumn, byte boardRow,
                                          bool selection)
        {
            byte index = GetBoardIndex(boardColumn, boardRow);

            if (ChessBoard.Squares[index].Piece == null)
            {
                return;
            }
            //if (ChessBoard.Squares[index].Piece.PieceColor != HumanPlayer)
            //{
            //    return;
            //}
            if (ChessBoard.Squares[index].Piece.PieceColor != WhoseMove)
            {
                return;
            }
            ChessBoard.Squares[index].Piece.Selected = selection;
        }

        public bool MovePiece(byte srcPosition, byte dstPosition)
        {
            //byte srcPosition = (byte)(sourceColumn + (sourceRow * 8));
            //byte dstPosition = (byte)(destinationColumn + (destinationRow * 8));

            Piece piece = ChessBoard.Squares[srcPosition].Piece;

            PreviousChessBoard = new Board(ChessBoard);


            Board.MovePiece(ChessBoard, srcPosition, dstPosition, ChessPieceType.Queen);

            PieceValidMoves.GenerateValidMoves(ChessBoard);


            //If there is a check in place, check if this is still true;
            if (piece.PieceColor == ChessPieceColor.White)
            {
                if (ChessBoard.WhiteCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }
            else if (piece.PieceColor == ChessPieceColor.Black)
            {
                if (ChessBoard.BlackCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }

            return true;

        }

        public bool MovePiece(byte sourceColumn, byte sourceRow, byte destinationColumn, byte destinationRow)
        {
            byte srcPosition = (byte)(sourceColumn + (sourceRow * 8));
            byte dstPosition = (byte)(destinationColumn + (destinationRow * 8));

            Piece piece = ChessBoard.Squares[srcPosition].Piece;

            PreviousChessBoard = new Board(ChessBoard);


            Board.MovePiece(ChessBoard, srcPosition, dstPosition, ChessPieceType.Queen);

            PieceValidMoves.GenerateValidMoves(ChessBoard);


            //If there is a check in place, check if this is still true;
            if (piece.PieceColor == ChessPieceColor.White)
            {
                if (ChessBoard.WhiteCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }
            else if (piece.PieceColor == ChessPieceColor.Black)
            {
                if (ChessBoard.BlackCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }

            return true;

        }

        public bool MovePiece(string algebraicNotation)
        {
            var move = GetMoveFromAlgebraicNotation(algebraicNotation);
            
            byte srcPosition = (byte)(move.SourceColumn + (move.SourceRow * 8));
            byte dstPosition = (byte)(move.DestColumn + (move.DestRow * 8));

            Piece piece = ChessBoard.Squares[srcPosition].Piece;

            PreviousChessBoard = new Board(ChessBoard);


            Board.MovePiece(ChessBoard, srcPosition, dstPosition, ChessPieceType.Queen);

            PieceValidMoves.GenerateValidMoves(ChessBoard);


            //If there is a check in place, check if this is still true;
            if (piece.PieceColor == ChessPieceColor.White)
            {
                if (ChessBoard.WhiteCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }
            else if (piece.PieceColor == ChessPieceColor.Black)
            {
                if (ChessBoard.BlackCheck)
                {
                    //Invalid Move
                    ChessBoard = new Board(PreviousChessBoard);
                    PieceValidMoves.GenerateValidMoves(ChessBoard);
                    return false;
                }
            }

            return true;
        }

        private static byte GetBoardIndex(byte BoardColumn, byte BoardRow)
        {
            return (byte)(BoardColumn + (BoardRow * 8));
        }

        public List<MovesInfo> GetBoardMoves()
        {
            List<MovesInfo> ListMoves = new List<MovesInfo>();
            for (int i = 0; i < ChessBoard.Squares.Length; i++)
            {
                if (ChessBoard.Squares[i].Piece != null)
                {
                    if (ChessBoard.Squares[i].Piece.PieceColor == ChessBoard.WhoseMove)
                    {
                        foreach (byte square in ChessBoard.Squares[i].Piece.ValidMoves)
                        {
                            ListMoves.Add(new MovesInfo((int)square % 8, (int)square / 8, (int)i % 8, (int)i / 8));
                            
                        }
                    }
                }
            }

            return ListMoves;
        }

        public double GetBoardScore(ChessPieceColor originalPlayer)
        {
            int pieceValueScore = 0;
            int mobilityScore = 0;
            int defendingPieceScore = 0;
            int centerControlScore = 0;
            int pawnStructureScore = 0;
            int[] ogPawnCols = new int[] {0, 0, 0, 0, 0, 0, 0, 0};
            int[] oppPawnCols = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
            int colindex = 0;
            double score = 0;

            for (int i = 0; i < ChessBoard.Squares.Length; i++)
            {
                if (ChessBoard.Squares[i].Piece != null)
                {
                   

                    if (ChessBoard.Squares[i].Piece.PieceColor == originalPlayer)
                    {
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Queen)
                        {
                            string asdf = "";
                        }

                        //piece value and mobility score
                        pieceValueScore += ChessBoard.Squares[i].Piece.PieceValue*10;
                        mobilityScore += (ChessBoard.Squares[i].Piece.ValidMoves.Count /2) / ChessBoard.Squares[i].Piece.PieceValue;

                        //check for doubled pawns
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                        {
                            ogPawnCols[colindex] ++;
                            if (ogPawnCols[colindex] > 1)
                                pawnStructureScore --;
                        }

                        //check for center of board control and blocked pawns
                        if ((i >= 25 && i <= 30) || (i >= 32 && i <= 37))
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Knight)
                                centerControlScore ++;

                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                            {
                                if( ChessBoard.Squares[i].Piece.LastValidMoveCount > 0)
                                {
                                    if (ChessBoard.Squares[i].Piece.IsDefendedBy > 0)
                                        pawnStructureScore++;
                                }else
                                    pawnStructureScore--;
                            }
                        }
                        else
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn && ChessBoard.Squares[i].Piece.LastValidMoveCount == 0)
                                pawnStructureScore --;
                        }

                        //attack/defend score
                        if (ChessBoard.Squares[i].Piece.nbIsAttackedBy <= ChessBoard.Squares[i].Piece.nbIsDefendedBy)
                            defendingPieceScore += ChessBoard.Squares[i].Piece.IsAttacking -ChessBoard.Squares[i].Piece.IsAttackedBy;
                        else
                            defendingPieceScore += ChessBoard.Squares[i].Piece.IsDefendedBy -ChessBoard.Squares[i].Piece.IsAttackedBy;

                        

                        //kingsafety
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.King &&
                                    ChessBoard.Squares[i].Piece.IsAttackedBy == 0)
                        {
                            if (originalPlayer == ChessPieceColor.White)
                            {
                                if (i == 1 || i == 2 || i == 0 || i == 5 || i == 6 || i == 7 )
                                    centerControlScore += 2;
                            }
                            else
                            {
                                if (i == 63 || i == 62 || i == 61 || i == 57 || i == 56 || i == 55)
                                    centerControlScore += 2;
                            }
                        }
                    }
                    else 
                    {
                        //piece value and mobility score
                        pieceValueScore -= ChessBoard.Squares[i].Piece.PieceValue*10;
                        mobilityScore -= (ChessBoard.Squares[i].Piece.ValidMoves.Count / 2) / ChessBoard.Squares[i].Piece.PieceValue;

                        //check for doubled pawns
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                        {
                            oppPawnCols[colindex]++;
                            if (oppPawnCols[colindex] > 1)
                                pawnStructureScore++;
                        }

                        //check for center of board control and blocked pawns
                        if ((i >= 25 && i <= 30) || (i >= 32 && i <= 37))
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Knight)
                                centerControlScore --;

                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                            {
                                if (ChessBoard.Squares[i].Piece.LastValidMoveCount > 0)
                                {
                                    if (ChessBoard.Squares[i].Piece.IsDefendedBy > 0)
                                        pawnStructureScore--;
                                }
                                else
                                    pawnStructureScore++;
                            }
                        }
                        else
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn && ChessBoard.Squares[i].Piece.LastValidMoveCount == 0)
                                pawnStructureScore ++;
                        }

                        //attack/defend score
                        if (ChessBoard.Squares[i].Piece.nbIsAttackedBy <= ChessBoard.Squares[i].Piece.nbIsDefendedBy)
                            defendingPieceScore -= ChessBoard.Squares[i].Piece.IsAttacking -ChessBoard.Squares[i].Piece.IsAttackedBy;
                        else
                            defendingPieceScore -= ChessBoard.Squares[i].Piece.IsDefendedBy -ChessBoard.Squares[i].Piece.IsAttackedBy;

                        //kingsafety
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.King &&
                                    ChessBoard.Squares[i].Piece.IsAttackedBy == 0)
                        {
                            //if ogplayer is white, opponent is black
                            if (originalPlayer == ChessPieceColor.White)
                            {
                                if (i == 63 || i == 62 || i == 61 || i == 57 || i == 56 || i == 55)
                                    centerControlScore -= 2;
                            }
                            else
                            {
                                if (i == 1 || i == 2 || i == 0 || i == 5 || i == 6 || i == 7)
                                    centerControlScore -= 2;
                                
                            }
                        }
                        
                    }

                }

                //increment col index
                colindex ++;
                if (colindex == 8)
                    colindex = 0;
            }

            //calculate total score
            //pieceValueScore
            //+ pawnStructureScore
            //+ mobilityScore
            //+ defendingPieceScore
            //+ centerControlScore
            score = 0.85 * pieceValueScore + 0.05 * pawnStructureScore + 0.02 * mobilityScore + 0.07 * centerControlScore + 0.01 * defendingPieceScore;
            //score = pieceValueScore + pawnStructureScore + mobilityScore + defendingPieceScore + centerControlScore;
            return score;
        }

        public Tuple<double, List<double>> GetBoardScore(ChessPieceColor originalPlayer, List<double> Weight)
        {
            int pieceValueScore = 0;
            int mobilityScore = 0;
            int defendingPieceScore = 0;
            int centerControlScore = 0;
            int pawnStructureScore = 0;
            int[] ogPawnCols = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
            int[] oppPawnCols = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };
            int colindex = 0;
            double score = 0;

            for (int i = 0; i < ChessBoard.Squares.Length; i++)
            {
                if (ChessBoard.Squares[i].Piece != null)
                {
                    if (ChessBoard.Squares[i].Piece.PieceColor == originalPlayer)
                    {
                        //piece value and mobility score
                        pieceValueScore += ChessBoard.Squares[i].Piece.PieceValue * 10;
                        mobilityScore += (ChessBoard.Squares[i].Piece.ValidMoves.Count / 2) / ChessBoard.Squares[i].Piece.PieceValue;

                        //check for doubled pawns
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                        {
                            ogPawnCols[colindex]++;
                            if (ogPawnCols[colindex] > 1)
                                pawnStructureScore--;
                        }

                        //check for center of board control and blocked pawns
                        if ((i >= 25 && i <= 30) || (i >= 32 && i <= 37))
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Knight)
                                centerControlScore++;

                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                            {
                                if (ChessBoard.Squares[i].Piece.LastValidMoveCount > 0)
                                {
                                    if (ChessBoard.Squares[i].Piece.IsDefendedBy > 0)
                                        pawnStructureScore++;
                                }
                                else
                                    pawnStructureScore--;
                            }
                        }
                        else
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn && ChessBoard.Squares[i].Piece.LastValidMoveCount == 0)
                                pawnStructureScore--;
                        }

                        //attack/defend score
                        if (ChessBoard.Squares[i].Piece.nbIsAttackedBy <= ChessBoard.Squares[i].Piece.nbIsDefendedBy)
                            defendingPieceScore += ChessBoard.Squares[i].Piece.IsAttacking - ChessBoard.Squares[i].Piece.IsAttackedBy;
                        else
                            defendingPieceScore += ChessBoard.Squares[i].Piece.IsDefendedBy - ChessBoard.Squares[i].Piece.IsAttackedBy;

                        //kingsafety
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.King &&
                                    ChessBoard.Squares[i].Piece.IsAttackedBy == 0)
                        {
                            if (originalPlayer == ChessPieceColor.White)
                            {
                                if (i == 1 || i == 2 || i == 0 || i == 5 || i == 6 || i == 7)
                                    centerControlScore += 2;
                            }
                            else
                            {
                                if (i == 63 || i == 62 || i == 61 || i == 57 || i == 56 || i == 55)
                                    centerControlScore += 2;
                            }
                        }
                    }
                    else
                    {
                        //piece value and mobility score
                        pieceValueScore -= ChessBoard.Squares[i].Piece.PieceValue * 10;
                        mobilityScore -= (ChessBoard.Squares[i].Piece.ValidMoves.Count / 2) / ChessBoard.Squares[i].Piece.PieceValue;

                        //check for doubled pawns
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                        {
                            oppPawnCols[colindex]++;
                            if (oppPawnCols[colindex] > 1)
                                pawnStructureScore++;
                        }

                        //check for center of board control and blocked pawns
                        if ((i >= 25 && i <= 30) || (i >= 32 && i <= 37))
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Knight)
                                centerControlScore--;

                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn)
                            {
                                if (ChessBoard.Squares[i].Piece.LastValidMoveCount > 0)
                                {
                                    if (ChessBoard.Squares[i].Piece.IsDefendedBy > 0)
                                        pawnStructureScore--;
                                }
                                else
                                    pawnStructureScore++;
                            }
                        }
                        else
                        {
                            if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.Pawn && ChessBoard.Squares[i].Piece.LastValidMoveCount == 0)
                                pawnStructureScore++;
                        }

                        //attack/defend score
                        if (ChessBoard.Squares[i].Piece.nbIsAttackedBy <= ChessBoard.Squares[i].Piece.nbIsDefendedBy)
                            defendingPieceScore -= ChessBoard.Squares[i].Piece.IsAttacking - ChessBoard.Squares[i].Piece.IsAttackedBy;
                        else
                            defendingPieceScore -= ChessBoard.Squares[i].Piece.IsDefendedBy - ChessBoard.Squares[i].Piece.IsAttackedBy;

                        //kingsafety
                        if (ChessBoard.Squares[i].Piece.PieceType == ChessPieceType.King &&
                                    ChessBoard.Squares[i].Piece.IsAttackedBy == 0)
                        {
                            //if ogplayer is white, opponent is black
                            if (originalPlayer == ChessPieceColor.White)
                            {
                                if (i == 63 || i == 62 || i == 61 || i == 57 || i == 56 || i == 55)
                                    centerControlScore -= 2;
                            }
                            else
                            {
                                if (i == 1 || i == 2 || i == 0 || i == 5 || i == 6 || i == 7)
                                    centerControlScore -= 2;

                            }
                        }

                    }

                }

                //increment col index
                colindex++;
                if (colindex == 8)
                    colindex = 0;
            }
            var weightArray = Weight.ToArray();
            //calculate total score
            score = weightArray[0] * pieceValueScore + weightArray[1] * pawnStructureScore + weightArray[2] * mobilityScore + weightArray[3] * centerControlScore + weightArray[4] * defendingPieceScore;

            return new Tuple<double, List<double>>(score, new List<double>() { pieceValueScore, pawnStructureScore, mobilityScore, defendingPieceScore, centerControlScore });
        }

        public string GetBoardFen(bool boardOnly = true)
        {
            return Board.Fen(boardOnly, ChessBoard);
        }
        public MovesInfo GetMoveFromAlgebraicNotation(string algebraicNotation)
        {
            string firstFile = "";
            string firstRank = "";
            string secondFile = "";
            string secondRank = "";
            string files = "abcdefgh";
            string ranks = "12345678";
            string pieces = "QRNBK";
            ChessPieceType promote = ChessPieceType.Queen;
            ChessPieceType currentPiece = ChessPieceType.Pawn;
            int destFile = -1;
            int destRank = -1;
            int sourceFile = -1;
            int sourceRank = -1;
            bool promoting = false;
            try
            {

                // castles are easy, so we check for them first
                if (algebraicNotation == "O-O")
                {
                    //king side castle
                    if (ChessBoard.WhoseMove == ChessPieceColor.Black)
                    {
                        destRank = 0;
                        destFile = 6;
                    }
                    else
                    {
                        destRank = 7;
                        destFile = 6;
                    }
                    currentPiece = ChessPieceType.King;
                }
                else if (algebraicNotation == "O-O-O")
                {
                    //queen side castle
                    if (ChessBoard.WhoseMove == ChessPieceColor.Black)
                    {
                        destRank = 0;
                        destFile = 2;
                    }
                    else
                    {
                        destRank = 0;
                        destFile = 2;
                    }
                    currentPiece = ChessPieceType.King;
                }
                else
                {
                    // a non castling move, so interate through the chars in the SAN token
                    for (int i = 0; i < algebraicNotation.Length; i++)
                    {
                        string st = algebraicNotation.Substring(i, 1);

                        // is this character a valid file?
                        if (files.Contains(st))
                        {
                            // is this the first time the token is referencing a file?
                            if (firstFile == "")
                                firstFile = st;
                            else
                                secondFile = st;
                        }

                        // is this character a valid rank?
                        if (ranks.Contains(st))
                        {
                            // is this the first time the token is referencing a rank?
                            if (firstRank == "")
                                firstRank = st;
                            else
                                secondRank = st;
                        }

                        // is this character representing a promotion?
                        if (st == "=")
                        {
                            promoting = true;
                        }
                        if (pieces.Contains(st))
                        {
                            if (promoting)
                            {
                                if (st == "N")
                                {
                                    promote = ChessPieceType.Knight;
                                }
                                else if (st == "B")
                                {
                                    promote = ChessPieceType.Bishop;
                                }
                                else if (st == "R")
                                {
                                    promote = ChessPieceType.Rook;
                                }
                            }
                            else
                            {
                                if (st == "Q")
                                {
                                    currentPiece = ChessPieceType.Queen;
                                }
                                else if (st == "K")
                                {
                                    currentPiece = ChessPieceType.King;
                                }
                                else if (st == "N")
                                {
                                    currentPiece = ChessPieceType.Knight;
                                }
                                else if (st == "B")
                                {
                                    currentPiece = ChessPieceType.Bishop;
                                }
                                else if (st == "R")
                                {
                                    currentPiece = ChessPieceType.Rook;
                                }
                            }
                        }
                    }

                    //now figure out the source and dest rank and file based on what was in the SAN token
                    if (secondFile == "")
                    {
                        destFile = fileToInt[firstFile];
                    }
                    else
                    {
                        sourceFile = fileToInt[firstFile];
                        destFile = fileToInt[secondFile];
                    }

                    if (secondRank == "")
                    {
                        destRank = 8 - Convert.ToInt16(firstRank);
                    }
                    else
                    {
                        sourceRank = 8 - Convert.ToInt16(firstRank);
                        destRank = 8 - Convert.ToInt16(secondRank);
                    }
                }

                if ((destRank == -1) && (destFile == -1))
                    throw new Exception("destination square is ambiguous");

                var possibleSquares = new List<Tuple<Piece, byte, byte>>();

                for (byte i = 0; i < ChessBoard.Squares.Length; i++)
                {
                    if (ChessBoard.Squares[i].Piece != null && ChessBoard.Squares[i].Piece.PieceColor == WhoseMove &&
                        ChessBoard.Squares[i].Piece.PieceType == currentPiece)
                    {
                        possibleSquares.Add(new Tuple<Piece, byte, byte>(ChessBoard.Squares[i].Piece, (byte)(i % 8), (byte)(i / 8)));
                    }
                }

                foreach (var square in possibleSquares)
                {
                    foreach (byte bs in square.Item1.ValidMoves)
                    {
                        if (bs % 8 == destFile && (byte)(bs / 8) == destRank)
                        {
                            if (sourceFile == -1 ||(sourceFile != -1 && sourceFile == square.Item2))
                            {
                                sourceFile = square.Item2;
                                sourceRank = square.Item3;
                                break;
                            }
                        }
                    }
                }

            }
            catch (Exception e)
            {
                throw new Exception(e.ToString());
            }

            return new MovesInfo(destFile, destRank, sourceFile, sourceRank);
        }
        #endregion
    }
}